package db;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;

/**
 * A Singleton class for the use and manipulation of the database. All 
 * access must use the <code>getInstance</code> method to access this class.
 */
public class Db{
	/**Keep track of the singleton*/
	private static Db singel = new Db();
	/**The connected session*/
	private static Connection connection;
	/**The connections statement OBJECT for executing SQL statements*/
	private static Statement statement;
	/**The state of the connection*/
	private static boolean connected;
	/**The JDBC driver name*/
	private static final String db 	= "com.mysql.jdbc.Driver";
	/**The mySQL database address*/
	private static final String 
		url = "jdbc:mysql://mysql.stud.ntnu.no/hildevd_FP2010";
	/**The mySQL database username*/
	private static final String bn 	= "hildevd_FP";
	/**The mySQL database password*/
	private static final String pw 	= "maria";
	/**
	 * Create the instance and connects to the database
	 * @throws ClassNotFoundException if the JDBC driver is missing
	 */
	private Db(){
		connect();
	}
	/**
	 * Establishes a connection with the database and sets up objects for 
	 * convenience methods.
	 */
	private void connect(){
		try {
			//Load mySQL JDBC driver
			Class.forName(db).newInstance();
			
			//Create objects for convenience methods
			connection 	= DriverManager.getConnection(url, bn, pw);
			statement 	= connection.createStatement();
			connected	= true;
		} catch (IllegalAccessException iae){
			iae.printStackTrace();
		} catch (SQLException e) {
			System.err.println("Database error: " + e.getMessage());
			e.printStackTrace();
		}catch (ClassNotFoundException e1) {
			System.err.println("Database driver error: Class not found");
			System.exit(-1);
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/**
	 * Method to gain access to the {@link DBManager Kokk_sql} singleton.
	 * @return the singleton instance
	 * @throws ClassNotFoundException if the singleton can`t be created.
	 */
	public static Db getInstance(){
			if(singel == null){
			   singel  = new Db();
			}
			return singel;
	}
	/** 
	 * Retrieves a {@link Connection Connection} object that is used to 
	 * communicate with the database
	 * @return Connection -The connection object for the communication 
	 * with the database
	 */
	public Connection getConnection(){
		if(!connected || connection == null)
			connect();
		return connection;
	}
	/**
	 *Retrieves a DatabaseMetaData object that contains metadata about the database 
	 *to which this Connection object represents a connection. The metadata includes 
	 *information about the database's tables, its supported SQL grammar, its stored 
	 *procedures, the capabilities of this connection, and so on.  
	 * @return a DatabaseMetaData object for this Connection
	 */
	public DatabaseMetaData getMetaData() throws SQLException{
		if(!connected)
			connect();
		try{
			return connection.getMetaData();
		}catch (SQLException e) {
			connected = false;
			throw e;
		}
	}
	/**
	 * Releases this Connection object's database and JDBC resources immediately 
	 * instead of waiting for them to be automatically released. It also destroys 
	 * this Singleton
	 */
	public void close(){
		try {
			connection.close();
			connected = false;
		} catch (SQLException e) {
			System.err.println("Database error: " + e.getMessage());
			System.exit(-1);
		}
	}
	/**
	 * Retrieves whether the connection to the database is active.
	 * @return boolean -True if there is a connection to the database
	 * @see Connection
	 */
	public boolean isConnected(){
		return connected;
	}
	/**
	 * Executes the given SQL statement, which returns a single ResultSet object.
	 * @param query - an SQL statement to be sent to the database, typically a static SQL SELECT statement 
	 * @return ResultSet object that contains the data produced by the given query; never null 
	 */
	public ResultSet executeQuery(String query) throws SQLException{
		if(!connected)
			connect();
		try{
			return statement.executeQuery(query);
		}catch (SQLException e) {
			connected = false;
			throw e;
		}
	}
	/**
	 * Executes the given SQL statement, which may be an INSERT, UPDATE, or DELETE 
	 * statement or an SQL statement that returns nothing, such as an SQL DDL statement. 
	 * @param update - an SQL Data Manipulation Language (DML) statement, such as 
	 * INSERT, UPDATE or DELETE; or an SQL statement that returns nothing, such as a DDL statement. 
	 * @return either (1) the row count for SQL Data Manipulation Language (DML) statements or 
	 * (2) 0 for SQL statements that return nothing 
	 */
	public int executeUpdate(String update) throws SQLException{
		if(!connected)
			connect();
		try{
			return statement.executeUpdate(update);
		}catch (SQLException e) {
			connected = false;
			throw e;
		}
	}
}
